﻿//#define USE_XMLDSIGEX

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml;
using XmlDSigEx;
using System.Security.Cryptography.X509Certificates;
using System.Security.Cryptography.Xml;
using System.Threading;
using System.Diagnostics;
using System.IO;
using System.Reflection;



namespace Console
{
    class Program
    {
        private static string input;

        static void Main(string[] args)
        {
            //input = GetEmbeddedContent("Console.SAML2Request.xml");
            input = GetEmbeddedContent("Console.Saml2SignedRequest.xml");
            int numOfThreads = 1;
            int numOfIterations = 10000;

            TestBasicVerify();

            Stopwatch sw = new Stopwatch();
            sw.Start();
            CountdownEvent evt = new CountdownEvent(numOfThreads);
            for (int i = 0; i < numOfThreads; i++)
            {
                ThreadStart del = new ThreadStart(delegate
                    {
                        for (int its = 0; its < numOfIterations; its++)
                        {
                            TestBasicVerify();
                        }
                        evt.Signal();
                    });
                Thread thread = new Thread(del);
                thread.Start();
            }
            evt.Wait();
            sw.Stop();
            double totalIterations = numOfThreads * numOfIterations;
            System.Console.WriteLine("{0} iterations completed in {1} milliseconds. {2} iterations per second.", totalIterations, sw.ElapsedMilliseconds, totalIterations / sw.ElapsedMilliseconds * 1000);
            System.Console.ReadLine();
        }

        private static string certThumbprint = "d3 c9 39 98 f6 b1 f5 9b c4 25 1e d5 de e2 36 2b ea 57 b0 d3";

        public static string GetEmbeddedContent(string resourceName)
        {
            using (Stream resourceStream =
                 Assembly.GetAssembly(typeof(Program)).GetManifestResourceStream(resourceName))
            {
                StreamReader reader = new StreamReader(resourceStream);
                return reader.ReadToEnd();
            }
        }

        public static void TestBasicSign()
        {
            X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            try
            {
                store.Open(OpenFlags.ReadOnly);
                var cert = store.Certificates.Find(X509FindType.FindByThumbprint, certThumbprint, false)[0];

                XmlDocument doc = new XmlDocument() { PreserveWhitespace = true };
                XmlReader reader = XmlReader.Create(new StringReader(input));
                doc.Load(reader);

#if USE_XMLDSIGEX
                XmlSigner signer = new XmlSigner(doc);
                signer.CanonicalisationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
                signer.SignatureMethod = SignedXml.XmlDsigRSASHA1Url;

                XmlDSigEx.Reference refr = signer.CreateReference();
                refr.Uri = "";
                refr.DigestMethod = SignedXml.XmlDsigSHA1Url;
                refr.AddTransform(SignedXml.XmlDsigEnvelopedSignatureTransformUrl);

                ISignatureAlgorithm algorithm = new RSAX509Algorithm(cert);
                var signature = signer.GetXml(algorithm);

                doc.DocumentElement.AppendChild(doc.ImportNode(signature, true));
#else
                SignedXml sXml = new SignedXml(doc);
                System.Security.Cryptography.Xml.Reference reference = new System.Security.Cryptography.Xml.Reference();
                reference.Uri = "";
                reference.DigestMethod = SignedXml.XmlDsigSHA1Url;
                reference.AddTransform(new XmlDsigEnvelopedSignatureTransform());
                sXml.AddReference(reference);

                sXml.SignedInfo.CanonicalizationMethod = SignedXml.XmlDsigExcC14NTransformUrl;
                sXml.SigningKey = cert.PrivateKey;
                sXml.ComputeSignature();

                XmlElement signature = sXml.GetXml();
                doc.DocumentElement.AppendChild(doc.ImportNode(signature, true));                
#endif
            }
            finally
            {
                store.Close();
            }
        }


        private static void TestBasicVerify()
        {
            XmlDocument signedDoc = new XmlDocument() { PreserveWhitespace = true };
            signedDoc.Load(XmlReader.Create(new StringReader(input)));


#if USE_XMLDSIGEX
            XmlSigner signer = new XmlSigner(signedDoc);
            bool result = signer.ValidateSignature(signedDoc.DocumentElement.LastChild as XmlElement);
#else
                SignedXml xml = new SignedXml(signedDoc);
                xml.LoadXml(signedDoc.DocumentElement.LastChild as XmlElement);
                bool result = xml.CheckSignature();                
#endif
        }
    }
}
